// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_GROUP_HPP_
#define _XBASE_GROUP_HPP_

#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>

#include "sstable.hpp"
#include "memory_table.hpp"
#include "table_schema.hpp"
#include "group_scanner.hpp"

namespace xbase {

	class group
		: private boost::noncopyable
	{
	public:
		typedef boost::shared_ptr<group> pointer;

		typedef std::map<std::string, table_schema::family_info> family_map_type;
	public:
		// 在指定的子表目录中，加载指定表的指定组
		// @p_tablet_path 子表的目录
		// @p_table_name 表名
		// @p_group_name 组名
		// @ 文件系统
		//
		// @return 返回加载后的组，失败返回空指针
		static
		pointer load (const std::string &p_tablet_path,
			      const std::string &p_table_name,
			      const std::string &p_group_name,
			      const uint64_t &tablet_id,
			      const std::string &p_tablet_name,
			      const std::string &start_row,
			      const std::string &end_row,
			      const table_schema::group_info &info,
			      const family_map_type &families);

		// 添加新的SSTable，并放到最后（或按顺序插入）
		void append (sstable::pointer p_sstable);

		~group();

		// 
		// 读写接口
		// 

		// 写入记录到内存表中
		void add(row_block::pointer &new_row_block) {
			m_memtable->add(new_row_block);
		}

		bool too_huge() const {
			return m_memtable->too_huge();
		}

		// 返回一个包含所有SSTable扫描器及内存表的扫描器的组合扫描器
		// 注意：返回空表示失败！
		group_scanner::pointer get_scanner (kv_scan_context::pointer);

		// recover record from log entry
		// template<typename BufferSequence>
		// int recover(const BufferSequence &data, std::size_t total_bytes) {
		// 	return m_memtable->add(data, total_bytes);
		// }
		void recover(row_block::pointer &row) {
			m_memtable->add(row);
		}
		
		std::string to_string () const;

		std::string group_name() const {
			return m_group_name;
		}
		std::string table_name() const {
			return m_table_name;
		}
		std::string tablet_name() const {
			return m_tablet_name;
		}

		// 是否需要主要紧缩
		bool need_major_compact() const;

		// 进行主要紧缩，将多个SSTable合并为一个后，根据该
		// SSTable大小确定是否需要分裂
		void major_compact();
		bool is_need_split() const;
		bool split(const std::string &p_midrow,
			   const std::string &p_path_a,
			   const uint64_t p_tablet_a_id,
			   const std::string &p_tablet_a_name,
			   const std::string &p_path_b,
			   const uint64_t p_tablet_b_id,
			   const std::string &p_tablet_b_name,
			   const uint64_t p_sstable_sequence_number);
		
		bool minor_compact(bool p_forced = false);

		// 用于周期性检查
		bool need_minor_compact() const {
			return m_memtable->need_minor_compact();
		}

		// 用于写记录后即时检查
		bool is_need_minor_compact_fastly() const {
			return m_memtable->is_need_minor_compact_fastly();
		}

		bool recover_compact();

		uint64_t max_sequence_number() const {
			return m_max_sequence_number;
		}

		uint64_t total_file_size_no_lock() const;

		std::string get_mid_row() const;

		uint32_t memory_table_size() const {
			return m_memtable->bytes();
		}

	protected:
		group(const std::string &p_table_name,
		      const std::string &p_group_name,
		      const uint64_t &tablet_id,
		      const std::string &p_tablet_name,
		      const fs::path &p_path,
		      const std::string &start_row,
		      const std::string &end_row,
		      const table_schema::group_info &info,
		      const family_map_type &families);

		group_scanner::pointer get_sstables_scanner (kv_scan_context::pointer);
		group_scanner::pointer get_sstables_scanner_no_lock (kv_scan_context::pointer);

		bool should_merge_compact() const;
		void merge_compact();

		// 即使文件数不足以主要紧缩，但若总数据量达到该值，也同样主要紧缩。
		uint64_t data_size_threshold() const {
			const uint64_t max_size = m_group_info.m_max_size_sstable;
			return max_size + max_size / 4; // 将max_size扩大25%
		}

	private:
		group(const group&);
		group &operator= (const group&);

	private:
		std::string m_table_name;
		std::string m_group_name;

		uint64_t m_tablet_id;
		std::string m_tablet_name;
		const boost::filesystem::path m_path;
		std::string m_start_row;
		std::string m_end_row;

		const table_schema::group_info m_group_info;
		const family_map_type m_family_list;
		const std::size_t m_lower_bound_of_max_num_sstable;

		// 按时间排序的SSTable，新生成的SSTable总添加到最后即可
		std::vector<sstable::pointer> m_sstables;
		uint64_t m_max_sequence_number;
		// 合并紧缩计数，取值范围[0，（最大SSTable数 － 最少合
		// 并SSTable数）)，超过最大值后，则合并紧缩转换为主要紧
		// 缩，并置merge_counter为SSTable个数(1或0)
		//
		// 初始值为组加载后的SSTable个数
		//
		// 每次合并紧缩，合并后面的（最大SSTable数 － 合并紧缩
		// 计数）个SSTable
		std::size_t m_merge_counter;
		mutable boost::shared_mutex m_sstables_lock;

		memory_table::pointer m_memtable;

		// TODO: 扫描缓存和删除缓存也在这里
	};

} // namespace xbase

#endif	// _XBASE_GROUP_HPP_

